package uk.ac.cam.juliet.zedcat.client;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 *
 * @author David Piggott
 * Modified for loading and writing from/to file by Chris
 * 
 */
public class Configuration {

    private HashMap<String, Object> _settings = new HashMap<String, Object>();

    public Configuration() {

        /*
         * Database configuration
         */
        _settings.put("databaseHost", new String("//localhost:3306/juliet"));
        _settings.put("databaseUser", new String("juliet"));
        _settings.put("databasePassword", new String("Oechahdi"));

        /*
         * Image Processing variables
         */
        _settings.put("backgroundAdaptationRate", new Float(0.1f));
        _settings.put("subtractionThreshold", new Integer(25));
        _settings.put("ignoreDisturbance", new Boolean(true));
        _settings.put("ignoreOnlyRegions", new Boolean(false));
        _settings.put("selectiveAdaptation", new Boolean(true));
        _settings.put("maxDisturbance", new Integer(50));
        _settings.put("minRegionSize", new Float(0.2f));

        /*
         * FrameViewer configuration
         */
        _settings.put("displayForegroundPixels", new Boolean(true));
        _settings.put("displayRegions", new Boolean(true));
        _settings.put("displayBoundingBoxes", new Boolean(true));


        /*
         * EventQuantise configuration
         */
        _settings.put("minEventInterval", new Integer(5000));
        _settings.put("quantisePeriod", new Integer(10));

        /*
         * FrameSource configuration
         */
        _settings.put("sourceType", new Boolean(true)); // 0 for webcamXP, 1 for AXIS M7001
        _settings.put("imageSource", new String("http://192.168.0.90"));

        /*
         * Read any settings from the configuration
         */
        readConfiguration();

        /*
         * Initialise the database
         */
        getDatabase();
    }

    private void readConfiguration() {
        try {
            FileInputStream configFile = new FileInputStream("config.txt");
            DataInputStream in = new DataInputStream(configFile);
            BufferedReader reader = new BufferedReader(new InputStreamReader(in));
            String currentLine;

            Pattern pattern = Pattern.compile("^([a-zA-Z]+)[ ]*:[ ]*(.*)");
            Matcher m;

            while ((currentLine = reader.readLine()) != null) {
                m = pattern.matcher(currentLine);
                if (m.matches()) {
                    String item = m.group(1);
                    String value = m.group(2).trim();
                    if (value.startsWith("\"")) {
                        _settings.put(item, value.substring(1, value.length() - 1));
                    } else if (value.compareToIgnoreCase("true") == 0) {
                        _settings.put(item, new Boolean(true));
                    } else if (value.compareToIgnoreCase("false") == 0) {
                        _settings.put(item, new Boolean(false));
                    } else if (value.contains(".")) {
                        _settings.put(item, Float.parseFloat(value));
                    } else {
                        _settings.put(item, Integer.parseInt(value));
                    }
                }
            }

            reader.close();
            in.close();
            configFile.close();

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void writeConfiguration() {
        try {
            FileWriter outputFile = new FileWriter("config.txt", false);
            BufferedWriter fob = new BufferedWriter(outputFile);
            for (String key : _settings.keySet()) {
                String fieldType = _settings.get(key).getClass().getName();
                if (fieldType.compareTo("java.lang.String") == 0) {
                    fob.write(key + ":\"" + ((String) _settings.get(key)) + "\"\n");
                } else if (fieldType.compareTo("java.lang.Boolean") == 0) {
                    if ((Boolean) _settings.get(key)) {
                        fob.write(key + ":true\n");
                    } else {
                        fob.write(key + ":false\n");
                    }
                } else if (fieldType.compareTo("java.lang.Integer") == 0) {
                    fob.write(key + ":" + ((Integer) _settings.get(key)).toString() + "\n");
                } else if (fieldType.compareTo("java.lang.Float") == 0) {
                    fob.write(key + ":" + ((Float) _settings.get(key)).toString() + "\n");
                }
            }
            fob.close();
            outputFile.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void setSetting(String name, Object value) {
        _settings.put(name, value);
        writeConfiguration();
    }

    /*
     * ImageSource getters
     */
    public URL getCameraJPEGLocation() {
        URL ImageURL = null;
        try {
            if ((Boolean) _settings.get("sourceType")) {
                ImageURL = new URL((String) _settings.get("imageSource") + "/jpg/image.jpg");
            } else {
                ImageURL = new URL((String) _settings.get("imageSource") + ":8080/cam_1.jpg");
            }
        } catch (MalformedURLException e) {
            System.out.println("Bad image source URL.");
        }
        return ImageURL;
    }

    public URL getCameraMJPEGLocation() {
        URL ImageURL = null;
        try {
            if ((Boolean) _settings.get("sourceType")) {
                ImageURL = new URL((String) _settings.get("imageSource") + "/mjpg/video.mjpg");
            } else {
                ImageURL = new URL((String) _settings.get("imageSource") + ":8080/cam_1.cgi");
            }
        } catch (MalformedURLException e) {
            System.out.println("Bad image source URL.");
        }
        return ImageURL;
    }
    private Database _db;

    public Database getDatabase() {
        if (_db == null) {
            _db = new Database(
                    (String) _settings.get("databaseHost"),
                    (String) _settings.get("databaseUser"),
                    (String) _settings.get("databasePassword"));
        }
        return _db;
    }

    public List<Hotspot> getHotspots() {
        return getDatabase().fetchHotspots(this);
    }

    /*
     * ImageWidth is needed by the Database to scale hotspots
     */
    public int ImageWidth = 0;

    /*
     * Motion detection getters
     */
    public float getBackgroundAdaptationRate() {                        // Fraction of the live image that should be used to update the background
        return (Float) _settings.get("backgroundAdaptationRate");
    }

    public int getSubtractionThreshold() {                              // Distance threshold in RGB space between values of live and
        return (Integer) _settings.get("subtractionThreshold");         // background pixels - below this difference pixels are considered
    }                                                                   // equal

    public boolean ignoreDisturbance() {                                // Whether to ignore images with more than
        return (Boolean) _settings.get("ignoreDisturbance");		// a specific ratio of foreground pixels
    }

    public boolean ignoreOnlyRegions() {                                // When doing selective background adaptation, shall
        return (Boolean) _settings.get("ignoreOnlyRegions");		// we only update pixels that were not foreground, or
    }                                                                   // only pixels that were not moving regions (after regions below
                                                                        // the threshold size have been discarded)
    
    public boolean selectiveAdaptation() {                              // True if background pixels should only be updated if they
        return (Boolean) _settings.get("selectiveAdaptation");          // were determined to be not movement (what we class as movement is
    }                                                                   // defined by ignoreOnlyRegions)

    public int maxDisturbance() {                                       // Maximum percentage of foreground pixels
        return (Integer) _settings.get("maxDisturbance");		// that are allowed before we stop trying
    }									// to grow regions

    public float getMinRegionSize() {                                   // Regions smaller than this value (a percentage of the total image size)
        return (Float) _settings.get("minRegionSize");                  // are discarded
    }

    /*
     * FrameViewer getters.
     */
    public boolean displayForegroundPixels() {
        return (Boolean) _settings.get("displayForegroundPixels");
    }

    public boolean displayRegions() {
        return (Boolean) _settings.get("displayRegions");
    }

    public boolean displayBoundingBoxes() {
        return (Boolean) _settings.get("displayBoundingBoxes");
    }

    /*
     * Event Quantisation getters
     */
    public int getMinEventInterval() {
        return (Integer) _settings.get("minEventInterval");
    }

    public int getQuantisePeriod() {
        return (Integer) _settings.get("quantisePeriod");
    }

    /*
     * Misc
     */
    public int getNullColour() {
        return 0;
    }

    public int getQueueSize() {
        return 1;
    }
}
